// Copyright (c) 2023 Presto Labs Pte. Ltd.
// Author: xguo, daniel

#pragma once

#include <memory>
#include <string>

#include <fmt/format.h>
#include <pybind11/functional.h>
#include <pybind11/numpy.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

#include "appcoin2/support/py_module/driver/py_order_update.h"
#include "coin2/exchange/base/order/order.h"

namespace py = pybind11;

namespace coin2::exchange::driver {
namespace impl {

using BaseOrderSubsystem = coin2::exchange::base::order::BaseOrderSubsystem;

class PyOrderSubsystem {
 public:
  explicit PyOrderSubsystem(BaseOrderSubsystem* os) : os_(os) {}
  ~PyOrderSubsystem() = default;

  std::string mea() const { return os_->mea().String(); }

  bool IsReady() const { return os_->is_ready(); }

  // return none or proc_order_id
  py::object SubmitOrder(py::dict py_order_spec) {
    auto order_spec = GenOrderSpecFromDict(os_, py_order_spec);
    if (!order_spec) {
      return py::none();
    }
    auto r = os_->gateway()->SubmitOrder(*order_spec);
    if (r) {
      return py::none();
    } else {
      return py::int_(*r);
    }
  }

  bool CancelOrder(int64_t proc_order_id) { return os_->gateway()->CancelOrder(proc_order_id); }

  auto GetAllWorkingOrders() const -> std::vector<PyOrderContext> {
    // TODO(daniel): better to return py::list or make copy?
    std::vector<PyOrderContext> working_order;
    for (auto* order : os_->gateway()->order_manager().GetAllWorkingOrders()) {
      working_order.push_back(PyOrderContext(order));
    }
    return working_order;
  }

 private:
  BaseOrderSubsystem* os_ = nullptr;
};

inline void AddPyOrderSystem(py::module* m) {
  py::class_<PyOrderSubsystem, std::shared_ptr<PyOrderSubsystem>>(*m, "_OrderSubsystem")
      .def_property_readonly("mea", &PyOrderSubsystem::mea)
      .def("is_ready", &PyOrderSubsystem::IsReady)
      .def("get_all_working_orders", &PyOrderSubsystem::GetAllWorkingOrders)
      .def("submit_order", &PyOrderSubsystem::SubmitOrder)
      .def("cancel_order", &PyOrderSubsystem::CancelOrder);
}

}  // namespace impl

}  // namespace coin2::exchange::driver
